package com.champrin.replicationofmyblockapix;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.champrin.replicationofmyblockapix.http.FinishRecord;
import com.champrin.replicationofmyblockapix.layout.Layout;
import com.champrin.replicationofmyblockapix.layout.QueryLayout;
import com.champrin.replicationofmyblockapix.tile.Position;
import com.champrin.replicationofmyblockapix.tile.Size;
import com.champrin.replicationofmyblockapix.tile.Tile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

public class BlockAPixView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private boolean isGaming = false;
    private boolean isBackToMenu = false;
    private final SurfaceHolder mSurfaceHolder;
    // Canvas对象
    private Canvas mCanvas;
    private final Paint mPaint = new Paint();

    private float tileLength; // 每个正方形格子的长度
    private final Size<Integer> screenSize = new Size<>(); // 屏幕宽高
    private final Size<Integer> gridSize = new Size<>(); // 横、纵格子数目
    private Tile[][] grids;
    private static final int INDENT_RATIO = 22; // 游戏区域的内缩距离比例
    private final Size<Integer> indentSize = new Size<>(); // 游戏区域的内缩距离
    private static final ArrayList<Integer> tileColors = new ArrayList<>(Arrays.asList(Color.BLACK, Color.BLUE, Color.RED, Color.GRAY));

    public BlockAPixView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT); //设置背景透明

        setZOrderOnTop(true); //使SurfaceView放到最顶层
        setFocusable(true); // 设置可获得焦点
        setFocusableInTouchMode(true);
        setKeepScreenOn(true); // 设置常亮
    }

    public void SetGridSize(int width, int height) {
        gridSize.x = width;
        gridSize.y = height;
        grids = new Tile[height][width];

        screenSize.x = this.getWidth();
        screenSize.y = this.getHeight();

        indentSize.x = screenSize.x / INDENT_RATIO / 2;
        indentSize.y = screenSize.y / INDENT_RATIO / 2;
        tileLength = (screenSize.x - 2.0f * indentSize.x) / gridSize.x; // 每个正方形格子的长度取决于宽
    }

    enum SpawnType {
        CreateBySQL,
        Random,
        SaveData
    }

    SpawnType spawnType;

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
        isGaming = true;
        isBackToMenu = true;
        new Thread(this).start();

        switch (spawnType) {
            case CreateBySQL:
                createBySQL();
                break;
            case Random:
                randomSpawn();
                break;
            case SaveData:
                continueGame();
                break;
        }
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
        isGaming = false;
    }

    @Override
    public void run() {
        while (isGaming) {
            if (!isBackToMenu)
                draw();
        }
    }

    public void setBackToMenu(boolean value) {
        isBackToMenu = value;
    }

    Tile lastDownNumberTile;
    Tile lastDownTile;
    Position<Integer> lastDownGridPoint = new Position<>(-1, -1); // 上一次点击的格子坐标
    Position<Integer> lastDownNumberTilePoint = new Position<>(-1, -1); // 上一次点击的带有颜色格子
    Position<Float> lastDownScreenPoint = new Position<>(-1.0f, -1.0f); // 上一次点击的屏幕坐标

    LinkedHashMap<Tile, int[]> chunks = new LinkedHashMap<>();
    int[] lastChunkArea = new int[4]; // minGridX-maxGridX-minGridY-maxGridY

    boolean isDownInitTile = false;

    boolean isDownColorTile = false;

    MotionEvent firstUp, secondDown;
    long firstUpTime, secondDownTime;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX(); // 获取手指移动的坐标
        float y = event.getY();
        Position<Integer> gridPoint = getTilePosition(x, y); // 获取格子坐标

        if (gridPoint.x == -1 && gridPoint.y == -1) // 没有点中格子，忽略
            return true;

        Tile tile = grids[gridPoint.y][gridPoint.x];
        int minGridX = 0, maxGridX = 0, minGridY = 0, maxGridY = 0;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 有三种Tile：已经被激活（被画上了颜色），没有被激活（是初始Tile），没有被激活（不是初始Tile）
                // 1. 判断是否被激活，是被激活的，判断这个是属于哪个区块的
                // 2. 没有被激活判断是不是初始Tile，不是则不理睬
                if (tile.activatedColor != -1) {
                    Tile seekTile = null;
                    boolean isSeek = false;
                    for (Map.Entry<Tile, int[]> entry : chunks.entrySet()) {
                        int[] area = entry.getValue();
                        if (gridPoint.x >= area[0] && gridPoint.x <= area[1] && gridPoint.y >= area[2] && gridPoint.y <= area[3]) {
                            isSeek = true;
                            seekTile = entry.getKey();
                            break;
                        }
                    }
                    if (isSeek) {
                        isDownColorTile = true;
                        lastDownNumberTile = seekTile;
                        lastDownNumberTilePoint = gridPoint;

                        if (firstUpTime != -1) {
                            secondDownTime = System.currentTimeMillis();
                            secondDown = event;
                            if (isConsideredDoubleTap()) { // 同一格连续点击两次表示清除该区域填充
                                int[] area = chunks.get(lastDownNumberTile);
                                assert area != null;
                                for (int i = area[0]; i <= area[1]; ++i) {
                                    for (int j = area[2]; j <= area[3]; ++j) {
                                        grids[j][i].activatedColor = -1;
                                    }
                                }
                                isDownColorTile = false;
                                chunks.remove(seekTile);
                            }
                            firstUpTime = -1;
                        }
                    }
                } else if (tile.initColor != 0) {
                    isDownInitTile = true;
                    tile.activatedColor = tile.initColor;
                    lastDownNumberTile = tile;
                    lastDownNumberTilePoint = gridPoint;
                    lastChunkArea = new int[]{gridPoint.x, gridPoint.x, gridPoint.y, gridPoint.y};
                    chunks.put(lastDownNumberTile, lastChunkArea);
                }

                lastDownScreenPoint.x = x;
                lastDownScreenPoint.y = y;
                lastDownGridPoint = gridPoint;
                lastDownTile = tile;
                break;
            case MotionEvent.ACTION_MOVE:
                if (!isDownInitTile && !isDownColorTile)
                    break;

                if (isDownInitTile) {
                    // 清除上一次移动所激活的颜色
                    minGridX = Math.min(lastDownGridPoint.x, lastDownNumberTilePoint.x);
                    maxGridX = Math.max(lastDownGridPoint.x, lastDownNumberTilePoint.x);
                    minGridY = Math.min(lastDownGridPoint.y, lastDownNumberTilePoint.y);
                    maxGridY = Math.max(lastDownGridPoint.y, lastDownNumberTilePoint.y);
                    // 记录上一次移动的区块
                    lastChunkArea = new int[]{minGridX, maxGridX, minGridY, maxGridY};

                    // 判断是否与其它区块碰撞
                    boolean isInOtherChunk = cheekInOtherChunk(lastDownNumberTile, gridPoint);

                    if (isInOtherChunk) {
                        // 改为上一次移动的区块
                        chunks.put(lastDownNumberTile, lastChunkArea);
                        break;
                    }

                    minGridX = Math.min(lastDownNumberTilePoint.x, gridPoint.x);
                    maxGridX = Math.max(lastDownNumberTilePoint.x, gridPoint.x);
                    minGridY = Math.min(lastDownNumberTilePoint.y, gridPoint.y);
                    maxGridY = Math.max(lastDownNumberTilePoint.y, gridPoint.y);

                    if ((maxGridX - minGridX + 1) * (maxGridY - minGridY + 1) <= lastDownNumberTile.initNumber) {
                        for (int i = minGridX; i <= maxGridX; ++i) {
                            for (int j = minGridY; j <= maxGridY; ++j) {
                                // grids[j][i]没有数字和没被激活，同时不在原有的矩形区域
                                if ((grids[j][i].activatedColor != -1 || grids[j][i].initNumber != 0) && !isInArea(lastDownNumberTile, new Position<>(i, j))) {
                                    isInOtherChunk = true;
                                    break;
                                }
                            }
                        }

                        if (isInOtherChunk) {
                            // 改为上一次移动的区块
                            chunks.put(lastDownNumberTile, lastChunkArea);
                            break;
                        }

                        for (int i = Math.min(lastDownGridPoint.x, lastDownNumberTilePoint.x); i <= Math.max(lastDownGridPoint.x, lastDownNumberTilePoint.x); ++i) {
                            for (int j = Math.min(lastDownGridPoint.y, lastDownNumberTilePoint.y); j <= Math.max(lastDownGridPoint.y, lastDownNumberTilePoint.y); ++j) {
                                grids[j][i].activatedColor = -1;
                            }
                        }

                        for (int i = minGridX; i <= maxGridX; ++i) {
                            for (int j = minGridY; j <= maxGridY; ++j) {
                                grids[j][i].activatedColor = lastDownNumberTile.initColor;
                            }
                        }
                        lastChunkArea = new int[]{minGridX, maxGridX, minGridY, maxGridY};
                        chunks.put(lastDownNumberTile, lastChunkArea);
                    } else {
                        // 改为上一次移动的区块
                        chunks.put(lastDownNumberTile, lastChunkArea);
                        break;
                    }
                } else {
                    // 判断是否与其它区块碰撞
                    boolean isInOtherChunk = cheekInOtherChunk(lastDownNumberTile, gridPoint);

                    if (isInOtherChunk) {
                        // 改为上一次移动的区块
                        chunks.put(lastDownNumberTile, lastChunkArea);
                        break;
                    }

                    int[] area = chunks.get(lastDownNumberTile);

                    assert area != null;
                    minGridX = Math.min(area[0], gridPoint.x);
                    maxGridX = Math.max(area[1], gridPoint.x);
                    minGridY = Math.min(area[2], gridPoint.y);
                    maxGridY = Math.max(area[3], gridPoint.y);

                    int newWidth = maxGridX - minGridX + 1;
                    int newHeight = maxGridY - minGridY + 1;

                    if (newWidth <= 0 || newHeight <= 0 || newWidth * newHeight > lastDownNumberTile.initNumber)
                        break;

                    for (int i = minGridX; i <= maxGridX; ++i) {
                        for (int j = minGridY; j <= maxGridY; ++j) {
                            // tile不为本身，同时该tile没有数字
                            if ((grids[j][i].activatedColor != -1 || grids[j][i].initNumber != 0) && !isInArea(lastDownNumberTile, new Position<Integer>(i, j))) {
                                isInOtherChunk = true;
                                break;
                            }
                        }
                    }

                    if (isInOtherChunk) {
                        // 改为上一次移动的区块
                        chunks.put(lastDownNumberTile, lastChunkArea);
                        break;
                    }

                    for (int i = minGridX; i <= maxGridX; ++i) {
                        for (int j = minGridY; j <= maxGridY; ++j) {
                            grids[j][i].activatedColor = lastDownNumberTile.initColor;
                        }
                    }

                    lastChunkArea = new int[]{minGridX, maxGridX, minGridY, maxGridY};
                    chunks.put(lastDownNumberTile, lastChunkArea);
                }

                lastDownGridPoint = gridPoint;
                break;
            case MotionEvent.ACTION_UP:
                isDownInitTile = false;
                isDownColorTile = false;

                firstUp = event;
                firstUpTime = System.currentTimeMillis();
                break;
        }
        return true;
    }

    private boolean isSameTile(Tile tile1, Tile tile2) {
        return Math.abs(tile1.startPosition.x - tile2.startPosition.x) < 1e-6 && Math.abs(tile1.startPosition.y - tile2.startPosition.y) < 1e-6;
    }

    private boolean isInArea(Tile keyTile, Position<Integer> targetTileGridPoint) {
        int[] area = chunks.get(keyTile);
        // 目标tile在某个矩形区域内
        assert area != null;
        return (targetTileGridPoint.x >= area[0] && targetTileGridPoint.x <= area[1] && targetTileGridPoint.y >= area[2] && targetTileGridPoint.y <= area[3]);
    }

    private boolean cheekInOtherChunk(Tile targetTile, Position<Integer> targetTileGridPoint) {
        // 判断是否与其它区块碰撞
        boolean isInOtherChunk = false;
        for (Map.Entry<Tile, int[]> entry : chunks.entrySet()) {
            int[] area = entry.getValue();
            // 目标tile在某个矩形区域内
            if (targetTileGridPoint.x >= area[0] && targetTileGridPoint.x <= area[1] && targetTileGridPoint.y >= area[2] && targetTileGridPoint.y <= area[3]) {
                // 不为本身所在的区块
                if (!isSameTile(entry.getKey(), targetTile)) {
                    isInOtherChunk = true;
                    break;
                }
            }
        }
        return isInOtherChunk;
    }

    private boolean isConsideredDoubleTap() {
        if (secondDownTime - firstUpTime > 100) {
            return false;
        }
        float deltaX = firstUp.getX() - secondDown.getX();
        float deltaY = firstUp.getY() - secondDown.getY();
        return deltaX * deltaX + deltaY * deltaY < 1000.0f;
    }

    private void draw() {
        try {
            mCanvas = mSurfaceHolder.lockCanvas();
            mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // 每帧清空画板，以便重新绘制
            drawTiles(null);
            if (!checkFinish()) {
                drawChunks();
                drawGrids();
            }
        } catch (Exception ignored) {
        } finally {
            // 对画布内容进行提交
            if (mCanvas != null) {
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    private boolean checkFinish() {
        int finishFlag = 0;
        for (int i = 0; i < gridSize.y; i++) {
            for (int j = 0; j < gridSize.x; j++) {
                Tile tile = grids[i][j];
                if (tile.activatedColor != -1)
                    ++finishFlag;
            }
        }
        boolean isFinish = (finishFlag >= (gridSize.x * gridSize.y));
//        Log.v("ACTION", finishFlag + " vs " + (gridSize.x * gridSize.y));
        if (isFinish) {
            Log.e("ACTION", "Finish Game！");
            FinishRecord.saveResult(layout_id);
            isGaming = false;
        }
        return isFinish;
    }

    private void drawGrids() {
        mPaint.reset();

        mPaint.setStyle(Paint.Style.STROKE);

        // 绘制边框
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(9);
        mCanvas.drawLine(indentSize.x, indentSize.y, indentSize.x, indentSize.y + gridSize.y * tileLength, mPaint);
        mCanvas.drawLine(indentSize.x + gridSize.x * tileLength, indentSize.y, indentSize.x + gridSize.x * tileLength, indentSize.y + gridSize.y * tileLength, mPaint);

        mCanvas.drawLine(indentSize.x, indentSize.y, indentSize.x + gridSize.x * tileLength, indentSize.y, mPaint);
        mCanvas.drawLine(indentSize.x, indentSize.y + gridSize.y * tileLength, indentSize.x + gridSize.x * tileLength, indentSize.y + gridSize.y * tileLength, mPaint);

        // 绘制内格
        mPaint.setColor(Color.GRAY);
        mPaint.setStrokeWidth(3);
        for (int i = 1; i < gridSize.x; i++) { //横向分隔 画竖线
            float startX = indentSize.x + i * tileLength;
            float startY = indentSize.y;
            mCanvas.drawLine(startX, startY, startX, startY + gridSize.y * tileLength, mPaint);
        }
        for (int i = 1; i < gridSize.y; i++) { //纵向分隔 画横线
            float startX = indentSize.x;
            float startY = indentSize.y + i * tileLength;
            mCanvas.drawLine(startX, startY, startX + gridSize.x * tileLength, startY, mPaint);
        }

        mPaint.reset();
        // 绘制格子
        for (int i = 0; i < gridSize.y; i++) {
            for (int j = 0; j < gridSize.x; j++) {
                float startX = indentSize.x + j * tileLength;
                float startY = indentSize.y + i * tileLength;
                float endX = startX + tileLength;
                float endY = startY + tileLength;
                float centerX = (startX + endX) * 0.5f;
                float centerY = (startY + endY) * 0.5f;

                Tile tile = grids[i][j];
                //mCanvas.drawCircle(centerX, centerY, 3, mPaint); // debug center
                if (tile.initNumber != 0) {
                    // 将文字用一个矩形包裹，进而算出文字的长和宽
                    mPaint.setTextSize((int) (tileLength * 0.69));
                    mPaint.setColor(tile.activatedColor != -1 ? Color.WHITE : tile.initColor);
                    Rect bounds = new Rect();
                    String numberString = String.valueOf(tile.initNumber);
                    mPaint.getTextBounds(numberString, 0, numberString.length(), bounds);
                    Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();

                    // 计算长宽
                    int x = getMeasuredWidth() / 2 - bounds.width() / 2;
                    int y = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;

                    // 将坐标原点移到控件中心
                    mCanvas.drawText(numberString, x - (screenSize.x * 0.5f - centerX), y - (screenSize.y * 0.5f - centerY), mPaint);
                }
            }
        }
    }

    private void drawTiles(Canvas mCanvas) {
        if (mCanvas == null) {
            mCanvas = this.mCanvas;
        }

        mPaint.reset();
        for (int i = 0; i < gridSize.y; i++) {
            for (int j = 0; j < gridSize.x; j++) {
                Tile tile = grids[i][j];
                if (tile.activatedColor == -1)
                    continue;
                mPaint.setColor(tile.activatedColor);
                mCanvas.drawRect(tile.startPosition.x, tile.startPosition.y, tile.endPosition.x, tile.endPosition.y, mPaint);
            }
        }
    }

    private void drawChunks() {
        mPaint.reset();
        mPaint.setColor(Color.WHITE);
        mPaint.setStrokeWidth(3);

        for (Map.Entry<Tile, int[]> entry : chunks.entrySet()) {
            int[] area = entry.getValue();
            Tile leftTopTile = grids[area[2]][area[0]];
            Tile rightBottomTile = grids[area[3]][area[1]];

            float minScreenX = leftTopTile.startPosition.x + indentSize.x * 0.25f;
            float maxScreenX = rightBottomTile.endPosition.x - indentSize.x * 0.25f;
            float minScreenY = leftTopTile.startPosition.y + indentSize.x * 0.25f;
            float maxScreenY = rightBottomTile.endPosition.y - indentSize.x * 0.25f;

            mCanvas.drawLine(minScreenX, minScreenY, maxScreenX, minScreenY, mPaint);
            mCanvas.drawLine(maxScreenX, minScreenY, maxScreenX, maxScreenY, mPaint);
            mCanvas.drawLine(maxScreenX, maxScreenY, minScreenX, maxScreenY, mPaint);
            mCanvas.drawLine(minScreenX, maxScreenY, minScreenX, minScreenY, mPaint);
        }
    }

    public void setRandomSpawn() {
        spawnType = SpawnType.Random;
    }

    private void randomSpawn() {
        SetGridSize(6, 6);

        Log.v("ACTION", "randomSpawn " + gridSize.y + "  " + gridSize.x);
        Log.v("ACTION", "indentSize " + indentSize.x + "  " + indentSize.y);
        Log.v("tileLength", "tileLength " + tileLength);

        // 分配格子坐标
        for (int i = 0; i < gridSize.y; i++) {
            for (int j = 0; j < gridSize.x; j++) {
                float startX = indentSize.x + j * tileLength;
                float startY = indentSize.y + i * tileLength;
                float endX = startX + tileLength;
                float endY = startY + tileLength;

                Tile tile;
                if (new Random().nextInt(6) != 2) {
                    tile = new Tile(startX, startY, endX, endY);
                } else {
                    int value = new Random().nextInt(30);
                    if (value == 0) {
                        tile = new Tile(startX, startY, endX, endY);
                    } else {
                        Integer color = tileColors.get(value % tileColors.size());
                        tile = new Tile(startX, startY, endX, endY, value, color);
                    }
                }
                grids[i][j] = tile;
            }
        }

        isBackToMenu = false;
    }

    private int layoutLevel;
    public void setCreateBySQL(int level) {
        spawnType = SpawnType.CreateBySQL;
        layoutLevel = level;
    }

    private int layout_id;
    private void createBySQL() {
        new Thread() {
            @Override
            public void run() {
//                Layout layout = QueryLayout.QueryLayoutRandom();
                Layout layout = QueryLayout.QueryLayoutByRandomLevel(layoutLevel);
                layout.transform();
                layout_id = layout.getLayout_id();
                Log.v("d", layout.toString());

                SetGridSize(layout.getCols(), layout.getRows());

                int[][] numberArray = layout.getNumberArray();
                int[][] colorArray = layout.getColorArray();

                for (int i = 0; i < gridSize.y; i++) {
                    for (int j = 0; j < gridSize.x; j++) {
                        float startX = indentSize.x + j * tileLength;
                        float startY = indentSize.y + i * tileLength;
                        float endX = startX + tileLength;
                        float endY = startY + tileLength;

                        Tile tile;
                        if (numberArray[i][j] == 0 && colorArray[i][j] == 0) {
                            tile = new Tile(startX, startY, endX, endY);
                        } else {
                            tile = new Tile(startX, startY, endX, endY, numberArray[i][j], colorArray[i][j]);
                        }
                        grids[i][j] = tile;
                    }
                }

                isBackToMenu = false;
            }
        }.start();
    }

    public Position<Integer> getTilePosition(float x, float y) {
        int gridX = Math.max(0, (int) ((x - indentSize.x) / tileLength));
        gridX = Math.min(gridX, gridSize.x - 1);

        int gridY = Math.max(0, (int) ((y - indentSize.y) / tileLength));
        gridY = Math.min(gridY, gridSize.y - 1);

        return new Position<Integer>(gridX, gridY);
    }

    public Bitmap saveBitmap() {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas mCanvas = new Canvas(bitmap);
        drawTiles(mCanvas);
        return Bitmap.createBitmap(bitmap, indentSize.x, indentSize.y, (int) (gridSize.x * tileLength), (int) (gridSize.y * tileLength));
    }

    public String dataString;
    public String chunksDataString;

    public void setContinueGame(String dataString, String chunksDataString) {
        this.dataString = dataString;
        this.chunksDataString = chunksDataString;
        spawnType = SpawnType.SaveData;
    }

    private void continueGame() {
        String[] strs = dataString.split("\\|");
        SetGridSize(Integer.parseInt(strs[1]), Integer.parseInt(strs[0]));

        // 读入grids
        for (int i = 0; i < gridSize.y; i++) {
            for (int j = 0; j < gridSize.x; j++) {
                String[] tileStrs = strs[2 + i * gridSize.x + j].split("=");
                float startX = Float.parseFloat(tileStrs[0]);
                float startY = Float.parseFloat(tileStrs[1]);
                float endX = Float.parseFloat(tileStrs[2]);
                float endY = Float.parseFloat(tileStrs[3]);
                int initNumber = Integer.parseInt(tileStrs[4]);
                int initColor = Integer.parseInt(tileStrs[5]);
                int activatedColor = Integer.parseInt(tileStrs[6]);

                Tile tile;
                if (initNumber == 0 && initColor == 0) {
                    tile = new Tile(startX, startY, endX, endY);
                } else {
                    tile = new Tile(startX, startY, endX, endY, initNumber, initColor);
                }
                tile.activatedColor = activatedColor;
                grids[i][j] = tile;
            }
        }

        // 读入chunks
        chunks.clear();
        if (!chunksDataString.equals("")) {
            strs = chunksDataString.split("\\|");
            for (String str : strs) {
                String[] tileStrs = str.split("=");
                int gridX = Integer.parseInt(tileStrs[0]);
                int gridY = Integer.parseInt(tileStrs[1]);
                int minGridX = Integer.parseInt(tileStrs[2]);
                int maxGridX = Integer.parseInt(tileStrs[3]);
                int minGridY = Integer.parseInt(tileStrs[4]);
                int maxGridY = Integer.parseInt(tileStrs[5]);
                chunks.put(grids[gridY][gridX], new int[]{minGridX, maxGridX, minGridY, maxGridY});
            }
        }

        isBackToMenu = false;
    }

    // 行 | 列 | 第一行第一列Tile | 第一行第二列Tile | 第一行第三列Tile | ....
    public String TransformGridsSaveData() {
        StringBuilder dataString = new StringBuilder();
        dataString.append(gridSize.y).append("|").append(gridSize.x).append("|");
        for (int i = 0; i < gridSize.y; i++) {
            for (int j = 0; j < gridSize.x; j++) {
                dataString.append(grids[i][j].ToSaveGameDataString()).append("|");
            }
        }

        return dataString.toString();
    }

    public String TransformChunksSaveData() {
        StringBuilder dataString = new StringBuilder();
        for (Map.Entry<Tile, int[]> entry : chunks.entrySet()) {
            Position<Integer> tilePoint = getTilePosition(entry.getKey().centerPosition.x, entry.getKey().centerPosition.y);
            int[] area = entry.getValue();
            dataString.append(tilePoint.x).append("=")
                    .append(tilePoint.y).append("=")
                    .append(area[0]).append("=")
                    .append(area[1]).append("=")
                    .append(area[2]).append("=")
                    .append(area[3]).append("|");
        }
        return dataString.toString();
    }
}
